Регулярные выражения и библиотека PCRE[Версия 2.0]Регулярные выражения являются мощнейшим средством анализа и разбора текстовых ресурсов на составляющие элементы. С помощью регулярных выражений можно с легкостью определять корректность вводимых данных, а также определять наличие или отсутствие определенных текстовых элементов. ВведениеРегулярные выражения (англ. regular expressions - это калька с английского, по-русски правильнее было бы назвать их шаблонами) - это специальные литерные строки из символов, описывающие определенное семейство искомых строк. Стандартом де-факто являются регулярные выражения используемые в языке Perl, их так и называют - PCRE (perl comparatible regular expression - регулярные выражения совместимые с языком Perl). В данной статье не ставится целью полностью описать синтаксис и область применения регулярных выражений - для этого есть много специальной документации, в частности большое количество документации по языку Perl. Статья является скорее всего введением в предмет, кратким описанием данной области и возможностей, которые предоставляет данный инструмент. Регулярные выражения могут быть применены в любом алгоритме где существует ввод и обработка текстовых данных. Регулярные выражения настолько облегчают труд, повышают эффективность программ и упрощают их, что совершенно непонятно, почему эти выражения до сих пор не введены в Windows API в качестве штатного средства, как это сделано например в стандарте POSIX. Хотя надо отметить, что какие-то работы в этом направлении ведутся. Использование регулярных выражений кардинально облегчает разработку, модификацию и сопровождение программ, так как в случае изменения синтаксиса и правил обрабатываемых данных, вы меняете только одну строчку, а не исправляете весь текст программы, модифицируя свой громоздкий конечный автомат, разбирающий входной поток. Пример регулярных выраженийДопустим, пользователь вводит адрес базы данных SQL-сервера Interbase. Как известно, этот адрес может быть оформлен в одном из четырех форматов.
Задача состоит в том, чтобы выполнить реализовать в программе следующие функции.
Для решения этих задач введем следующие регулярные выражения. Эти выражения выглядят устрашающе, хотя если разобраться поэлементно, ничего страшного в них нет.
Будем проверять введенную пользователем строку на соответствие одному из вышеприведенных шаблонов. Если введенная строка соответствует шаблону, то будем считать, что это и есть соответствующий путь. Если введенная строка не соответствует ни одному из вышеприведенных шаблонов, будем считать, что это есть последний, четвертый вариант (его тоже нужно проверить по шаблону, но это опустим). Вот краткий "словарик" по элементам регулярных выражений. Для подробного ознакомления с структурой регулярных выражений обратитесь к оригинальной документации к библиотеке PCRE.
При выполнении регулярного выражения, если соответствующая строка будет успешно найдена, процедура поиска вернет три элемента. Первая - вся строчка, котороя удовлетворяет всему регулярному выражению; вторая и третья - то, что попадает в круглые скобки (подшаблоны), то есть имя компьютера и путь к базе данных без посторонних пробельных символов. Таким образом все четыре задачи успешно решаются лишь одним вызовом соответствующей функции. Библиотека PCREОдной из самых распространенных библиотек для работы с регулярными выражениями является мультиплатформенная библиотека PCRE (www.pcre.org), созданная Philip Hazel. Эта библиотека используется множеством проектов, включая проекты Python, Apache, Postfix, KDE, Analog, PHP, Ferite. Библиотека практически полностью совместима с Perl, и поэтому вы можете использовать всю богатую коллекцию документации к языку Perl. Библиотека скомпилирована компилятором Borland C++ 5.5, и в виде объектных модулей подключена к интерфейсному Delphi-файлу. Существует множество портированных под Delphi версий этой библиотеки, но большинство из них страдают теми или иными недостатками. Многие из них вынуждают таскать за собой дополнительные DLL библиотеки, а те, которые эти библиотеки связывают статически, портированы часто некорректно, без учета многих особенностей, что вызывает некорректную работу со сложными регулярными выражениями или выражениями на языках, отличных от английского. Здесь предлагается полнофункциональная, статически линкующаяся библиотека PCRE, поддерживающая локальные кодировки и интернациональную кодировку UTF-8. В комплекте идет пример, поясняющий работу этой библиотеки. <<< Портированная библиотека PCRE 4.1 и пример к ней Использование библиотеки PCREИспользование библиотеки PCRE сводится к использованию всего трех функций. Сначала регулярное выражение нужно скомпилировать, то есть перевести его из текстового вида в бинарный вид, понятный внутренним процедурам библиотеки. Компиляция регулярного выражения в бинарный вид намного убыстряет последующие операции поиска и анализа текста. Кроме того, при компиляции происходит проверка регулярного выражения на корректность. Компиляция осуществляется функцией pcre_compile(). Функция возвращает указатель на внутреннюю структуру анализатора. В случае ошибки, функция возвращает нулевой указатель, а в переданных переменных Error и ErrorPos - позицию ошибочного символа в регулярном выражении. ... const RE_SAMPLE = '(?i)^Phone: (\d\d\d\-\d\d\-\d\d)'; var RE : TPCRE; Error : PChar; ErrorPos : Integer; Patterns : array [0..19] of TMatchPattern; TextBuffer : string; begin ... // Компилируем выражение RE := pcre_compile(RE_SAMPLE, 0, Error, ErrorPos, PCRE_LOCALE_TABLE); // Компиляция прошла удачно? if RE = nil then Exit; ... После того, как регулярное выражение скомпилировано, им можно пользоваться для поиска текстовых элементов. Поиск выполняется функцией pcre_exec(). В функцию передаются: указатель на скомпилированное регулярное выражение, указатель на буфер в котором располагается анализируемый текст, размер этого буфера, указатель на массив маркеров, размер массива маркеров. Маркеры - это указатели начала и окончания найденного текста в текстовом буфере. Именно в этот массив маркеров процедура будет заносить координаты найденных фрагментов текста. В случае успешного выполнения, функция вернет количество найденных фрагментов текста. Число найденных фрагментов текста должно быть равно количеству подшаблонов (парных круглых скобок) в регулярном выражении плюс один (само регулярное выражение полностью). В нашем случае функция должна вернуть значение 2, так как в регулярном выражении есть один подшаблон, а массив маркеров должен иметь 2 проинициализированных значения. Маркер Patterns[0] указывает на начало и окончание фрагмента, соответствующего всему регулярному выражению полностью (например "Phone: 123-45-67"). Маркер Patterns[1] будет указывать на фрагмент, соответствующий вложенному подшаблону (то есть "123-45-67"). По этим координатам можно выбрать искомый фрагмент из текстового буфера, только нужно помнить, что маркерные координаты начинаются с 0, а индекс символов в Delphi-строке начинается с 1. ... // Выполняем поиск выражения if pcre_exec(RE, nil, TextBuffer, Length(TextBuffer), 0, 0, @Patterns[0], High(Patterns)+1) > 0 then begin // Получаем номер телефона PhoneNumber := Copy(TextBuffer, Patterns[1].Start + 1, Patterns[1].Next - Patterns[1].Start); end; ... После того, как все действия с регулярным выражением выполнены, необходимо освободить связанную с ним память. ... // Освобождаем скомпилированное выражение pcre_release(RE); ...
© Николай Мазуркин, 1999-2003. При копировании и размещении любых материалов, указание авторства и источника обязательно.
|